#include <common.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <fh_mc_dma.h>
#include <linux/compiler.h>

//#define MC_DMA_DEBUG 
#if defined(MC_DMA_DEBUG)
#define FH_MC_DMA_DEBUG(fmt, args...) printf(fmt, ##args);
#else
#define FH_MC_DMA_DEBUG(fmt, args...)
#endif


#define FH_MC_DMA_ASSERT(expr) if (!(expr)) { \
        printf("Assertion failed! %s:line %d\n", \
        __func__, __LINE__); \
        while (1)   \
            ;       \
        }

#define DMA_CONTROLLER_NUMBER (1)
#define FH_MC_CHANNEL_MAX_TRANSFER_SIZE (32 * 0x100000) //max 128MB one time.here for safe ,here set 32M incase max width_32bit * 32Msize

#ifndef BIT
#define BIT(x) (1 << (x))
#endif


/*********************************
 *
 * 
 *
 *********************************/
/* this is the ip reg offset....don't change!!!!!!! */
#define DW_MC_DMA_MAX_NR_CHANNELS 32
#define DW_MC_DMA_MAX_HAND_SHAKE_NO 64
/*
 * Redefine this macro to handle differences between 32- and 64-bit
 * addressing, big vs. little endian, etc.
 */
#define DW_REG(name)  \
    u32 name; \
    u32 __pad_##name

/* Hardware register definitions. */
struct dw_mc_dma_chan_regs
{
	u32 pause;//0
	u32 req;
	u32 cfg;
	u32 interrupt;
	u32 src_addr;//10
	u32 dst_addr;
	u32 frag_len;
	u32 blk_len;
	u32 trsc_len;//20
	u32 trsf_step;
	u32 wrap_ptr;
	u32 wrap_to;
	u32 llist_ptr;//30
	u32 frag_step;
	u32 src_blk_step;
	u32 dst_blk_step;
};

struct dw_mc_dma_regs
{

	u32 pause;//0
	u32 frag_wait;
	u32 pend_0_en;
	u32 pend_1_en;
	u32 int_raw_stat;//10
	u32 int_mask_stat;
	u32 req_stat;
	u32 en_stat;
	u32 debug_stat;//20
	u32 arb_sel_stat;
	u32 ch_cfg_grp_1;
	u32 ch_cfg_grp_2;
	u32 ch_arprot;//30
	u32 ch_awprot;
	u32 ch_prot_flag;
	u32 global_prot;
	u32 pend_0_port;//40
	u32 pend_1_port;
	u32 reqid_0_port;
	u32 reqid_1_port;
	u32 sync_sec_n_normal;//50
	u32 cnt_ch_sel;
	u32 total_trans_cnt_1;
	u32 total_trans_cnt_2;
	u32 rev_0[1000];
	struct dw_mc_dma_chan_regs ch[DW_MC_DMA_MAX_NR_CHANNELS];
	u32 rev_1[0x200];
	u32 hand_cid[DW_MC_DMA_MAX_HAND_SHAKE_NO];
};

struct dw_mc_dma
{
    void *regs;
};

enum mc_dma_req_mode{
	FRAGMENT,
	BLOCK,
	TRANSACTION,
	LINKLIST
};


enum mc_dma_ahb_size{
	BYTE,
	HALFWORD,
	WORD,
	DWORD
};

#define __dma_raw_writeb(v, a) (*(volatile unsigned char *)(a) = (v))
#define __dma_raw_writew(v, a) (*(volatile unsigned short *)(a) = (v))
#define __dma_raw_writel(v, a) (*(volatile unsigned int *)(a) = (v))

#define __dma_raw_readb(a) (*(volatile unsigned char *)(a))
#define __dma_raw_readw(a) (*(volatile unsigned short *)(a))
#define __dma_raw_readl(a) (*(volatile unsigned int *)(a))

#define dw_readl(dw, name) \
    __dma_raw_readl(&(((struct dw_mc_dma_regs *)dw->regs)->name))
#define dw_writel(dw, name, val) \
    __dma_raw_writel((val), &(((struct dw_mc_dma_regs *)dw->regs)->name))
#define dw_readw(dw, name) \
    __dma_raw_readw(&(((struct dw_mc_dma_regs *)dw->regs)->name))
#define dw_writew(dw, name, val) \
    __dma_raw_writew((val), &(((struct dw_mc_dma_regs *)dw->regs)->name))

#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
//DMA PAUSE register
#define DMA_PAUSE		BIT(0)
#define DMA_PAUSE_STAT		BIT(2)
#define GLB_REG_CLK_EN		BIT(16)
#define CHNL_REG_CLK_EN		BIT(17)
#define REQ_CID_CLK_EN		BIT(18)
#define INT_REG_CLK_EN		BIT(19)
#define AXI_MST_CLK_EN		BIT(20)
#define AUDIO_CNT_CLK_EN		BIT(21)

#define BLK_LEN_DUMMY					10
#define TRSC_LEN_DUMMY					10
#define FRAG_LEN_DUMMY					10

//channel def
#define CHAN_PAUSE	1
#define CHAN_ACTIVE	0
#define CHAN_PAUSE_BIT_MASK	1
#define LLIST_EN					(1<<4)

#define CH_ENABLE					1

#define CH_FRAGMENT_INT_EN				(0x1<<0)
#define CH_BLK_INT_EN					(0x1<<1)
#define CH_TRSC_INT_EN					(0x1<<2)
#define CH_LLIST_INT_EN					(0x1<<3)
#define CH_CFG_ERR_INT_EN				(0x1<<4)

#define CH_ALLINTRC_EN_MASK				CH_FRAGMENT_INT_EN|\
							CH_BLK_INT_EN|\
							CH_TRSC_INT_EN|\
							CH_LLIST_INT_EN|\
							CH_CFG_ERR_INT_EN

//desc def
#define BLK_LEN_MASK					0x1ffff
#define FRAG_LEN_MASK					0x1ffff
#define TRSC_LEN_MASK					0xfffffff

#define REQ_MODE_SHIFT					24
#define REQ_MODE_MASK					0x3

#define SRC_DST_AHB_SIZE_MASK			0xf
#define DST_AHB_SIZE_SHIFT				28
#define SRC_AHB_SIZE_SHIFT				30
#define ADDR_FIX_EN_SHIFT				20
#define ADDR_FIX_SEL_SHIFT				21
#define ADDR_WRAP_EN_SHIFT				22

#define WORD_STEP					0x4
#define DST_TRSF_STEP_SHIFT				16
#define TRSF_STEP_MASK					0xffffffff
#define LLIST_END						1
#define NOT_LLIST_END					0
#define LLIST_END_SHIFT					19

#define SWT_MODE_SHIFT              26
#define SWT_MODE_MASK               3

#define CHN_TRSC_LEN_LLIST_NODE_INT_EN			(0x1<<31)
#define CHN_TRSC_LEN_LLIST_NODE_INT_FRAG		(0x1<<28)
#define CHN_TRSC_LEN_LLIST_NODE_INT_BLK			(0x1<<29)
#define CHN_TRSC_LEN_LLIST_NODE_INT_TRSC		(0x1<<30)


#define ISR_LINK_DONE_RAW_STAT_BIT		(0x1<<11)

#define LEN_BOUND					0x80
// #define FRAGMENT_S					0x4
// #define FRAGMENT_B					0x80//0x100

#define DMA_LLI_SIZE        4096
static __attribute__((aligned(64))) struct mc_dma_lli g_dma_rx_lli[DMA_LLI_SIZE];
static __attribute__((aligned(64))) struct mc_dma_lli g_dma_tx_lli[DMA_LLI_SIZE];


#define ACTIVE_CHANNLE	0

struct dw_mc_dma g_mc_dma_obj;
struct mc_dma_lli *p_mc_dma_tx_lli = 0;
struct mc_dma_lli *p_mc_dma_rx_lli = 0;



static void mc_dma_clk_init(struct dw_mc_dma *mc_dma_obj){
	//SET_REG_M(0x10000000, BIT(1) | BIT(3) | BIT(5), BIT(1) | BIT(3) | BIT(5));
}

static void mc_dma_reset(struct dw_mc_dma *mc_dma_obj)
{

}

static void mc_dma_ch_pause_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 val){
	int ret;

	ret = dw_readl(mc_dma_obj, ch[no].pause);
	ret &= ~(CHAN_PAUSE_BIT_MASK);
	ret |= val;
	dw_writel(mc_dma_obj, ch[no].pause, ret);
}

static void mc_dma_enable(struct dw_mc_dma *mc_dma_obj)
{
	u32 ret;

	ret = dw_readl(mc_dma_obj, pause);
	ret |= (GLB_REG_CLK_EN | CHNL_REG_CLK_EN | 
			REQ_CID_CLK_EN | INT_REG_CLK_EN | 
			AXI_MST_CLK_EN | AUDIO_CNT_CLK_EN);
	dw_writel(mc_dma_obj, pause, ret);
}

static void mc_dma_ch_enable(struct dw_mc_dma *mc_dma_obj, u32 no){
	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].cfg);
	ret |= CH_ENABLE;
	dw_writel(mc_dma_obj, ch[no].cfg, ret);

}

static int mc_dma_ch_get_isr_status(struct dw_mc_dma *mc_dma_obj, u32 no){
	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].interrupt);
	return ret;
}

static void mc_dma_ch_clear_isr_status(struct dw_mc_dma *mc_dma_obj, u32 no){
	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].interrupt);
	ret |= (0x1f << 24);
	dw_writel(mc_dma_obj, ch[no].interrupt, ret);
}



static void mc_dma_ch_disable(struct dw_mc_dma *mc_dma_obj, u32 no){
	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].cfg);
	ret &= ~CH_ENABLE;
	dw_writel(mc_dma_obj, ch[no].cfg, ret);
}

static void mc_dma_ch_isr_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 enable)
{
	u32 ret;
	ret = dw_readl(mc_dma_obj, ch[no].interrupt);
	ret &= ~CH_ALLINTRC_EN_MASK;
	ret |= enable;
	dw_writel(mc_dma_obj, ch[no].interrupt, ret);
}


void mc_dma_ch_llist_en(struct dw_mc_dma *mc_dma_obj, u32 no){

	u32 ret;
	ret = dw_readl(mc_dma_obj, ch[no].cfg);
	ret |= LLIST_EN | (1<<5);
	dw_writel(mc_dma_obj, ch[no].cfg, ret);
}


void mc_dma_ch_blk_len_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 len){
	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].blk_len);
	ret &= ~BLK_LEN_MASK;
	ret |= len;
	dw_writel(mc_dma_obj, ch[no].blk_len, ret);

}

void mc_dma_ch_trsc_len_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 len){

	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].trsc_len);
	ret &= ~TRSC_LEN_MASK;
	ret |= len;
	dw_writel(mc_dma_obj, ch[no].trsc_len, ret);

}

void mc_dma_ch_frag_len_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 len){

	u32 ret;

	ret = dw_readl(mc_dma_obj, ch[no].frag_len);
	ret &= ~FRAG_LEN_MASK;
	ret |= len;
	dw_writel(mc_dma_obj, ch[no].frag_len, ret);

}

void mc_dma_ch_request(struct dw_mc_dma *mc_dma_obj, u32 no, u32 val){

	dw_writel(mc_dma_obj, ch[no].req, val);
}

void mc_dma_ch_llist_addr_set(struct dw_mc_dma *mc_dma_obj, u32 no, u32 list_addr){

	dw_writel(mc_dma_obj, ch[no].llist_ptr, list_addr);
}

void mc_dma_desc_set_src(struct mc_dma_lli *desc,u32 val){
	desc->src_addr = val;
}

void mc_dma_desc_set_dst(struct mc_dma_lli *desc,u32 val){
	desc->dst_addr = val;
}

void mc_dma_desc_set_trans_len(struct mc_dma_lli *desc, u32 len){
	desc->trans_len &= ~TRSC_LEN_MASK;
	desc->trans_len |= len;
}


void mc_dma_desc_set_blk_len(struct mc_dma_lli *desc, u32 len){
	desc->blk_len &= ~BLK_LEN_MASK;
	desc->blk_len |= len;
}

void mc_dma_desc_set_frag_len(struct mc_dma_lli *desc, u32 len){
	desc->frag_len &= ~FRAG_LEN_MASK;
	desc->frag_len |= len;
}

void mc_dma_desc_set_req_mode(struct mc_dma_lli *desc,u32 val){

	desc->frag_len &= ~(REQ_MODE_MASK<<REQ_MODE_SHIFT);
	desc->frag_len |= val<<REQ_MODE_SHIFT;
}


void mc_dma_desc_set_ahb_size(struct mc_dma_lli *desc,u32 src_size,u32 dest_size){
	desc->frag_len &= ~(SRC_DST_AHB_SIZE_MASK<<DST_AHB_SIZE_SHIFT);
	desc->frag_len |= src_size<< SRC_AHB_SIZE_SHIFT|dest_size<<DST_AHB_SIZE_SHIFT;
}

void mc_dma_desc_set_inc_mode(struct mc_dma_lli *desc, u32 src_inc, u32 dst_inc){

	if((src_inc == DW_DMA_SLAVE_DEC) || (dst_inc == DW_DMA_SLAVE_DEC))
		FH_MC_DMA_ASSERT(0);
	//only one side could be in fix mode....
	if((src_inc == DW_DMA_SLAVE_FIX) && (dst_inc == DW_DMA_SLAVE_FIX))
		FH_MC_DMA_ASSERT(0);
	
	if((src_inc == DW_DMA_SLAVE_INC) && (dst_inc == DW_DMA_SLAVE_INC)){
		//src inc & dst inc
		desc->frag_len &= ~(1 << ADDR_FIX_EN_SHIFT);
	}
	else if(src_inc == DW_DMA_SLAVE_INC){
		//src inc & dst fix
		desc->frag_len |= (1 << ADDR_FIX_EN_SHIFT);
		desc->frag_len |= 1 << ADDR_FIX_SEL_SHIFT;
	}
	else{
		desc->frag_len |= (1 << ADDR_FIX_EN_SHIFT);
		desc->frag_len &= ~(1 << ADDR_FIX_SEL_SHIFT);
	}

}

void mc_dma_desc_set_wrap_disable(struct mc_dma_lli *desc){
	desc->frag_len &= ~(1<<ADDR_WRAP_EN_SHIFT);
}

void mc_dma_desc_set_trsf_step(struct mc_dma_lli *desc,u32 src_step,u32 dest_step){
	desc->trsf_step &= ~TRSF_STEP_MASK;
	desc->trsf_step |= dest_step<<DST_TRSF_STEP_SHIFT|src_step;
}


void mc_dma_desc_set_step(struct mc_dma_lli *desc,u32 frag_step,u32 src_blk_step,u32 dest_blk_step){
	desc->frag_step = frag_step;
	desc->src_blk_step = src_blk_step;
	desc->dst_blk_step = dest_blk_step;
}


void mc_dma_desc_set_swtich_mode(struct mc_dma_lli *desc,u32 mode){
	desc->frag_len &= ~(SWT_MODE_MASK << SWT_MODE_SHIFT);
	mode &= SWT_MODE_MASK;
	desc->frag_len |= (mode << SWT_MODE_SHIFT);
}

void mc_dma_desc_set_llist_end(struct mc_dma_lli *desc,u32 val){
	if(val == LLIST_END)
		desc->frag_len |= 1<<LLIST_END_SHIFT;
	else
		desc->frag_len &= ~(1<<LLIST_END_SHIFT);
}


void mc_dma_desc_set_isr_disable(struct mc_dma_lli *desc){
	desc->trans_len &= ~CHN_TRSC_LEN_LLIST_NODE_INT_EN;
}

void mc_dma_desc_bind_next_desc(struct mc_dma_lli *desc,u32 val){
	desc->llist_ptr = val;
}


static u32 get_fragment_len(u32 len){

	u32 fg_len;
	if(len <= LEN_BOUND)
		fg_len = len;
	else{
		fg_len = LEN_BOUND;
	}
	return fg_len;

}

void dma_init(void){
	int i;

    g_mc_dma_obj.regs = (void *)DMA0_REG_BASE;
    p_mc_dma_tx_lli = (struct mc_dma_lli *)&g_dma_tx_lli[0];
    p_mc_dma_rx_lli = (struct mc_dma_lli *)&g_dma_rx_lli[0];
	mc_dma_clk_init(&g_mc_dma_obj);
	mc_dma_reset(&g_mc_dma_obj);
	for(i = 0; i < DW_MC_DMA_MAX_NR_CHANNELS; i++){
		mc_dma_ch_isr_set(&g_mc_dma_obj, i , 0);
		mc_dma_ch_pause_set(&g_mc_dma_obj, i, CHAN_ACTIVE);
		mc_dma_ch_disable(&g_mc_dma_obj, i);
		mc_dma_ch_clear_isr_status(&g_mc_dma_obj, i);
	}

	mc_dma_enable(&g_mc_dma_obj);
}


void *get_dma_tx_lli_head(void){
	return (void *)p_mc_dma_tx_lli;
}

void *get_dma_rx_lli_head(void){
	return (void *)p_mc_dma_rx_lli;
}

void wait_dma_xfer_done(u32 channel){

	u32 isr_channel_x;

    do{
        isr_channel_x = mc_dma_ch_get_isr_status(&g_mc_dma_obj, channel);
    }while((isr_channel_x & ISR_LINK_DONE_RAW_STAT_BIT) != ISR_LINK_DONE_RAW_STAT_BIT);
	mc_dma_ch_clear_isr_status(&g_mc_dma_obj, channel);
}


static void dump_lli(struct mc_dma_lli *p_lli)
{

	FH_MC_DMA_DEBUG("lli add is [%08x]\n",(int)p_lli);
	FH_MC_DMA_DEBUG("\nSAR: 0x%08x DAR: 0x%08x FRAG_LEN: 0x%08x BLK_LEN: 0x%08x\n\
TRANS_LEN: 0x%08x TRANS_STEP: 0x%08x WRAP_PTR: 0x%08x WRAP_TO: 0x%08x\n\
LIST_PTR: 0x%08x FRAG_STEP: 0x%08x  SRC_BLK_STEP: 0x%08x  DST_BLK_STEP: 0x%08x\n",
		(p_lli->src_addr),
		(p_lli->dst_addr),
		(p_lli->frag_len),
		(p_lli->blk_len),
		(p_lli->trans_len),
		(p_lli->trsf_step),
		(p_lli->wrap_ptr),
		(p_lli->wrap_to),
		(p_lli->llist_ptr),
		(p_lli->frag_step),
		(p_lli->src_blk_step),
		(p_lli->dst_blk_step));
}

static u32 cal_lli_size(struct dma_transfer *p_transfer)
{

    u32 lli_number                = 0;
    u32 channel_max_trans_per_lli = 0;
    u32 c_msize;
    c_msize = FH_MC_CHANNEL_MAX_TRANSFER_SIZE;
    channel_max_trans_per_lli = (p_transfer->period_len != 0) ? 
    (MIN(p_transfer->period_len, c_msize)) : (c_msize);
    lli_number = (p_transfer->trans_len % channel_max_trans_per_lli) ? 1 : 0;
    lli_number += p_transfer->trans_len / channel_max_trans_per_lli;
    FH_MC_DMA_DEBUG("cal lli size is %x\n",lli_number);
    return lli_number;

}

void mc_dma_ctl_init(u32 *low, u32 *high){

}

void mc_dma_cfg_init(u32 *low, u32 *high){

}

u32 fix_frag_len(struct dma_transfer *dma_trans_desc){
	u32 ret = 4;
	u32 parse_msize = 0;
	if(dma_trans_desc->ot_len_flag == USR_DEFINE_ONE_TIME_LEN){
		switch (dma_trans_desc->fc_mode){
		case DMA_P2M:
		case DMA_M2M:
			return dma_trans_desc->src_msize;
		case DMA_M2P:
			return dma_trans_desc->dst_msize;
		default:
			break;
		}
	}

    switch (dma_trans_desc->fc_mode)
    {
	case DMA_P2M:
    case DMA_M2M:
		if(dma_trans_desc->src_msize == DW_DMA_SLAVE_MSIZE_1)
			parse_msize = 0;
		else
			parse_msize = dma_trans_desc->src_msize + 1;
		ret = (1 << dma_trans_desc->src_width) * (1 << parse_msize);
        break;
    case DMA_M2P:
		if(dma_trans_desc->dst_msize == DW_DMA_SLAVE_MSIZE_1)
			parse_msize = 0;
		else
			parse_msize = dma_trans_desc->dst_msize + 1;
		ret = (1 << dma_trans_desc->dst_width) * (1 << parse_msize);
        break;

    default:
        break;
    }

	return ret;
}

void handle_single_transfer(struct dma_transfer *p_transfer,void *p_lli_in){

    u32 i;
    u32 lli_cal_size;
	u32 frag_len;
    struct dw_mc_dma *temp_dwc;
    u32 temp_src_add = 0;
    u32 temp_dst_add = 0;
    u32 trans_total_len = 0;
    u32 temp_trans_size = 0;
    u32 max_trans_size = 0;;
    temp_dwc = &g_mc_dma_obj;
    struct mc_dma_lli *p_lli = 0;
    struct dma_transfer *dma_trans_desc = p_transfer;

	p_transfer->trans_len = p_transfer->trans_len << dma_trans_desc->src_width;

    trans_total_len = p_transfer->trans_len;
    lli_cal_size = cal_lli_size(p_transfer);
    FH_MC_DMA_ASSERT(lli_cal_size <= DMA_LLI_SIZE);

    memset((void *)p_lli_in, 0,lli_cal_size * sizeof(struct mc_dma_lli));
    p_lli = (struct mc_dma_lli *)p_lli_in;
    max_trans_size = FH_MC_CHANNEL_MAX_TRANSFER_SIZE;
    if(p_transfer->period_len != 0){
        max_trans_size = MIN(max_trans_size, p_transfer->period_len);
    }
	mc_dma_ch_disable(&g_mc_dma_obj, dma_trans_desc->channel_number);

    for (i = 0; i < lli_cal_size; i++)
    {

        switch (dma_trans_desc->dst_inc_mode)
        {
			case DW_DMA_SLAVE_INC:
				temp_dst_add =
					dma_trans_desc->dst_add +
					i * max_trans_size;
				break;
			case DW_DMA_SLAVE_DEC:
				temp_dst_add =
					dma_trans_desc->dst_add -
					i * max_trans_size;
				break;
			case DW_DMA_SLAVE_FIX:
				temp_dst_add = dma_trans_desc->dst_add;
				break;
        }

        switch (dma_trans_desc->src_inc_mode)
        {
			case DW_DMA_SLAVE_INC:
				temp_src_add =
					dma_trans_desc->src_add +
					i * max_trans_size;
				break;
			case DW_DMA_SLAVE_DEC:
				temp_src_add =
					dma_trans_desc->src_add -
					i * max_trans_size;
				break;
			case DW_DMA_SLAVE_FIX:
				temp_src_add = dma_trans_desc->src_add;
				break;
        }
        if(p_transfer->src_reload_flag == ADDR_RELOAD){
            temp_src_add = dma_trans_desc->src_add;
        }
        if(p_transfer->dst_reload_flag == ADDR_RELOAD){
            temp_dst_add = dma_trans_desc->dst_add;
        }
		mc_dma_desc_set_src(&p_lli[i], temp_src_add);
		mc_dma_desc_set_dst(&p_lli[i], temp_dst_add);
        /* para ctl */
        temp_trans_size = (trans_total_len / max_trans_size)
                                ? max_trans_size
                                : (trans_total_len % max_trans_size);
        trans_total_len -= temp_trans_size;
		frag_len = fix_frag_len(p_transfer);
		FH_MC_DMA_DEBUG("frag_len is %x\n",frag_len);
		//frag_len = get_fragment_len(temp_trans_size);
		//frag_len = temp_trans_size;
		mc_dma_desc_set_trans_len(&p_lli[i], temp_trans_size);
		mc_dma_desc_set_blk_len(&p_lli[i], frag_len);
		mc_dma_desc_set_frag_len(&p_lli[i], frag_len);
		if(dma_trans_desc->fc_mode == DMA_M2M)
			mc_dma_desc_set_req_mode(&p_lli[i], LINKLIST);
		else
			mc_dma_desc_set_req_mode(&p_lli[i], FRAGMENT);
		mc_dma_desc_set_ahb_size(&p_lli[i], dma_trans_desc->src_width ,dma_trans_desc->dst_width);
		mc_dma_desc_set_trsf_step(&p_lli[i], 1 << dma_trans_desc->src_width, 1 << dma_trans_desc->dst_width);
		mc_dma_desc_set_wrap_disable(&p_lli[i]);
		mc_dma_desc_set_inc_mode(&p_lli[i],dma_trans_desc->src_inc_mode, dma_trans_desc->dst_inc_mode);
		mc_dma_desc_set_swtich_mode(&p_lli[i], dma_trans_desc->data_switch);
		mc_dma_desc_set_step(&p_lli[i], 0, 0, 0);
		mc_dma_desc_set_isr_disable(&p_lli[i]);
		if (trans_total_len > 0){
			mc_dma_desc_set_llist_end(&p_lli[i], NOT_LLIST_END);
			mc_dma_desc_bind_next_desc(&p_lli[i], (u32)&p_lli[i + 1]);
		}
		else{
			mc_dma_desc_set_llist_end(&p_lli[i], LLIST_END);
		}
		dump_lli(&p_lli[i]);
    }

    switch (dma_trans_desc->fc_mode)
    {
    case DMA_M2M:
		mc_dma_ch_request(&g_mc_dma_obj, dma_trans_desc->channel_number, 1);
        break;
    case DMA_M2P:
		mc_dma_ch_request(&g_mc_dma_obj, dma_trans_desc->channel_number, 0);
		dw_writel(temp_dwc, hand_cid[dma_trans_desc->dst_per], dma_trans_desc->channel_number + 1);
        break;
    case DMA_P2M:
		mc_dma_ch_request(&g_mc_dma_obj, dma_trans_desc->channel_number, 0);
		dw_writel(temp_dwc, hand_cid[dma_trans_desc->src_per], dma_trans_desc->channel_number + 1);
        break;

    default:
        break;
    }

	// mc_dma_ch_blk_len_set(&g_mc_dma_obj, dma_trans_desc->channel_number,BLK_LEN_DUMMY);
	// mc_dma_ch_trsc_len_set(&g_mc_dma_obj, dma_trans_desc->channel_number,TRSC_LEN_DUMMY);
	// mc_dma_ch_frag_len_set(&g_mc_dma_obj, dma_trans_desc->channel_number,FRAG_LEN_DUMMY);

	mc_dma_ch_llist_en(&g_mc_dma_obj, dma_trans_desc->channel_number);
	mc_dma_ch_llist_addr_set(&g_mc_dma_obj, dma_trans_desc->channel_number, (u32)&p_lli[0]);
	//print_buffer(0x8002000, (void *)0x8002000, 4, 0x100, 4);
	mc_dma_ch_enable(&g_mc_dma_obj, dma_trans_desc->channel_number);

}

